package org.googlecode.viewt.core.tools.contants;


import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;

import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.ValidationException;
import org.googlecode.viewt.core.tools.contants.types.ConstantDef;
import org.googlecode.viewt.core.tools.contants.types.Constants;
import org.googlecode.viewt.core.tools.contants.types.Display;
import org.googlecode.viewt.core.tools.contants.types.Item;
import org.googlecode.viewt.core.tools.contants.types.Loader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ConstantUtil
{
  private static Logger logger = LoggerFactory.getLogger(ConstantUtil.class);
  public static final String DEFAULT_OUTPUT_ENCODING = "GBK";

  public static Constants loadConfig(String cfgFile, String prePackName)
  {
    Constants constantsDef = null;
    try
    {
      Reader in = new InputStreamReader(new FileInputStream(cfgFile));
      constantsDef = Constants.unmarshal(in);
      String defaultPackage = prePackName + "." + constantsDef.getProjectName().toLowerCase() + "." + constantsDef.getModuleName().toLowerCase() + ".constant";
      ConstantDef[] constants = constantsDef.getConstantDef();
      int size = (null == constants) ? 0 : constants.length;
      for (int i = 0; i < size; ++i)
      {
        ConstantDef def = constants[i];
        if (def.getClassName().indexOf(46) < 0)
          def.setClassName(defaultPackage + "." + def.getClassName());
      }
    }
    catch (FileNotFoundException fnfEx)
    {
      logger.error("Can not find constant config:" + cfgFile + ", check your config", fnfEx);
      return null;
    }
    catch (MarshalException marshalEx)
    {
    	marshalEx.printStackTrace();
      logger.error("Unmarshal constant config:" + cfgFile + " fail, check your config", marshalEx);
      return null;
    }
    catch (ValidationException validateEx)
    {
      logger.error("Validate constant config:" + cfgFile + " fail, check your config", validateEx);
      return null;
    }
    logger.debug("constantsDef: " + (constantsDef==null));
    return constantsDef;
  }

  public static boolean validateConfig(Constants constantsDef)
  {
    if (("".equals(constantsDef.getProjectName().trim())) || ("".equals(constantsDef.getModuleName().trim())))
    {
      logger.error("Missing project or module name, constant config invalid");
      return false;
    }

    ConstantDef[] constants = constantsDef.getConstantDef();
    int size = (null == constants) ? 0 : constants.length;
    for (int i = 0; i < size; ++i)
    {
      ConstantDef constant = constants[i];

      if ("".equals(constant.getClassName().trim()))
      {
        logger.error("Missing class name, constant config invalid");
        return false;
      }

      if ((null != constant.getReloadDef()) && (((null == constant.getAlias()) || ("".equals(constant.getAlias())))))
      {
        logger.error("Missing alias name for reloadable constant:" + constant.getClassName());
        return false;
      }

      Item[] items = constant.getItem();
      int len = (null == items) ? 0 : items.length;
      for (int j = 0; j < len; ++j)
      {
        Item item = items[j];
        if ((!("".equals(item.getKey().trim()))) && (!("".equals(item.getValue().trim()))))
          continue;
        logger.error("Missing item key or value for constant:" + constant.getClassName());
        return false;
      }

      if ((null == constant.getReloadDef()) || (null == constant.getReloadDef().getLoader()))
        continue;
      Loader loader = constant.getReloadDef().getLoader();
      if ((!("".equals(loader.getNamedQuery().trim()))) && (!("".equals(loader.getKey().trim()))) && (!("".equals(loader.getValue().trim())))) {
        continue;
      }
      logger.error("Missing query, key or value of constant:" + constant.getClassName());
      return false;
    }

    return true;
  }

  public static String[] outputEncodings(Constants constantsDef)
  {
    List encodingList = new ArrayList();
    ConstantDef[] defs = constantsDef.getConstantDef();
    for (int i = 0; i < defs.length; ++i)
    {
      Item[] items = defs[i].getItem();
      for (int j = 0; j < items.length; ++j)
      {
        Display[] displays = items[j].getDisplay();
        for (int k = 0; k < displays.length; ++k)
        {
          Display disp = displays[k];
          String encoding = disp.getEncoding();
          if (null == encoding) {
            encoding = "GBK";
          }
          if (!(encodingList.contains(encoding))) {
            encodingList.add(encoding);
          }
        }
      }
    }
    return ((String[])encodingList.toArray(new String[0]));
  }

  public static ConstantDef[] constantsByEncoding(String encoding, Constants constantsDef)
  {
    List constantList = new ArrayList();
    ConstantDef[] defs = constantsDef.getConstantDef();
    for (int i = 0; i < defs.length; ++i)
    {
      Item[] items = defs[i].getItem();
      for (int j = 0; j < items.length; ++j)
      {
        Display[] displays = items[j].getDisplay();
        int k = 0;
        for (k = 0; k < displays.length; ++k)
        {
          Display disp = displays[k];
          if ((((null != disp.getEncoding()) || (!("GBK".equals(encoding))))) && (!(encoding.equals(disp.getEncoding())))) {
            continue;
          }
          constantList.add(defs[i]);
          break;
        }

        if (k < displays.length)
          break;
      }
    }
    return ((ConstantDef[])constantList.toArray(new ConstantDef[0]));
  }

  public static String[] localesByEncoding(String encoding, ConstantDef constant)
  {
    List localeList = new ArrayList();
    Item[] items = constant.getItem();
    for (int i = 0; i < items.length; ++i)
    {
      Display[] displays = items[i].getDisplay();
      for (int j = 0; j < displays.length; ++j)
      {
        Display disp = displays[j];
        if ((((null != disp.getEncoding()) || (!("GBK".equals(encoding))))) && (((!(encoding.equals(disp.getEncoding()))) || 
          (localeList.contains(disp.getLocale()))))) continue;
        localeList.add(disp.getLocale());
      }
    }

    return ((String[])localeList.toArray(new String[0]));
  }

  public static String resourceFile(String destPath, String className, String locale)
  {
    String fileName = shortClassName(className) + "Resource";
    if (null != locale) {
      fileName = fileName + "_" + locale.toString();
    }
    return getPackagePath(destPath, className) + File.separator + fileName + ".properties.bak";
  }

  public static String dataConfigFile(String destPath, String moduleName)
  {
    if (destPath.endsWith(File.separator)) {
      return destPath + "constant" + File.separator + moduleName + ".xml";
    }
    return destPath + File.separator + "constant" + File.separator + moduleName + ".xml";
  }

  public static String shortClassName(String className)
  {
    return className.substring(className.lastIndexOf(46) + 1);
  }

  public static String getPackagePath(String basePath, String className)
  {
    String[] packageSeg = getPackageName(className).split("[.]");
    String path = "";
    for (int i = 0; i < packageSeg.length; ++i)
    {
      if (i != 0)
        path = path + File.separator;
      path = path + packageSeg[i];
    }

    if (basePath != null) {
      path = basePath + File.separator + path;
    }
    return path;
  }

  public static String getPackageName(String className)
  {
    int index = className.lastIndexOf(46);
    if (index < 0) {
      return null;
    }
    return className.substring(0, index);
  }

  public static String fullJavaFileName(String basePath, String className)
  {
    return getPackagePath(basePath, className) + File.separator + shortJavaFileName(className);
  }

  public static String shortJavaFileName(String className)
  {
    return shortClassName(className) + ".java";
  }
}